package com.cc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cc.base.PageResponse;
import com.cc.base.ResponseResult;
import com.cc.enums.HttpsCode;
import com.cc.enums.RedisEnmu;
import com.cc.exception.BusinessException;
import com.cc.mapper.MenuMapper;
import com.cc.mapper.RoleMapper;
import com.cc.mapper.UserMapper;
import com.cc.pojo.domain.Menu;
import com.cc.pojo.domain.Role;
import com.cc.pojo.domain.Router;
import com.cc.pojo.dto.MenuDto;
import com.cc.pojo.dto.MenuPageDto;
import com.cc.pojo.vo.MenuOptionsVo;
import com.cc.pojo.vo.MenuVo;
import com.cc.pojo.vo.OptionsVo;
import com.cc.service.MenuService;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {
    @Resource
    private UserMapper userMapper;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private MenuMapper menuMapper;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 添加菜单
     *
     * @param menuDto
     * @return
     */
    @Override
    public ResponseResult<String> addMenu(MenuDto menuDto) {
        //1.检查参数
        if (StrUtil.isAllBlank(menuDto.getName(), menuDto.getPath())) {
            throw new BusinessException(HttpsCode.PARAMS_ERROR);
        }
        //2.添加菜单
        Menu menu = BeanUtil.copyProperties(menuDto, Menu.class);
        boolean save = save(menu);
        if (!save) {
            throw new BusinessException(HttpsCode.ADD_FAILED);
        }
        return ResponseResult.ok();
    }

    /**
     * 修改菜单
     *
     * @param menuDto
     * @return
     */
    @Override
    public ResponseResult<String> updateMenu(MenuDto menuDto) {
        //1.检查参数
        if (menuDto.getMenuId() == null) {
            throw new BusinessException(HttpsCode.PARAMS_ERROR, "菜单id为空");
        }
        //2.修改菜单
        Menu menu = BeanUtil.copyProperties(menuDto, Menu.class);
        boolean is = updateById(menu);
        if (!is) {
            throw new BusinessException(HttpsCode.MODIFICATION_FAILED);
        }
        return ResponseResult.ok();
    }

    /**
     * 分页查询菜单
     *
     * @param menuPageDto
     * @return
     */
    @Override
    public ResponseResult<PageResponse<MenuVo>> getMenuPage(MenuPageDto menuPageDto) {
        //1.检查参数
        menuPageDto.checkPage();
        //2.分页查询
        Page<Menu> page = page(new Page<>(menuPageDto.getPageNum(), menuPageDto.getPageSize()),
                Wrappers.<Menu>lambdaQuery()
                        .like(StrUtil.isNotBlank(menuPageDto.getPath()), Menu::getPath, menuPageDto.getPath())
                        .like(StrUtil.isNotBlank(menuPageDto.getName()), Menu::getName, menuPageDto.getName())
                        .like(StrUtil.isNotBlank(menuPageDto.getComponent()), Menu::getComponent, menuPageDto.getComponent())
                        .like(StrUtil.isNotBlank(menuPageDto.getTitleZhCn()), Menu::getTitleZhCn, menuPageDto.getTitleZhCn())
                        .like(StrUtil.isNotBlank(menuPageDto.getTitleEnUs()), Menu::getTitleEnUs, menuPageDto.getTitleEnUs())
                        .eq(StrUtil.isNotBlank(menuPageDto.getStatus()), Menu::getStatus, menuPageDto.getStatus())
        );
        //获取所有目录菜单
        List<Menu> records = page.getRecords();
        List<MenuVo> mlList = records.stream()
                .filter(menu -> menu.getMenuType().equals("M"))
                .map(item -> BeanUtil.copyProperties(item, MenuVo.class))
                .toList();
        for (MenuVo menuVo : mlList) {
            ArrayList<MenuVo> children = new ArrayList<>();
            for (Menu record : records) {
                if (record.getParentId().equals(menuVo.getMenuId())) {
                    children.add(BeanUtil.copyProperties(record, MenuVo.class));
                }
            }
            menuVo.setChildren(children);
        }
        //3.响应数据
        return ResponseResult.ok(new PageResponse<>(page, mlList));
    }

    /**
     * 获取所有的目录级别
     *
     * @return
     */
    @Override
    public ResponseResult<List<OptionsVo>> tableOfContents() {
        List<Menu> menuList = list(Wrappers.<Menu>lambdaQuery().eq(Menu::getMenuType, "M"));
        List<OptionsVo> optionsVoList = new ArrayList<>();
        for (Menu menu : menuList) {
            optionsVoList.add(new OptionsVo(menu.getTitleZhCn(), menu.getMenuId().toString()));
        }
        return ResponseResult.ok(optionsVoList);
    }

    /**
     * 获取动态路由
     *
     * @return
     */
    @Override
    public ResponseResult<List<Router>> getMenuList(int userId) {
        String result = (String) redisTemplate.opsForValue().get(RedisEnmu.CC_MENU_ROUTE_LIST + userId);
        if (StrUtil.isNotBlank(result)) {
            List<Router> list = JSONUtil.toList(result, Router.class);
            return ResponseResult.ok(list);
        }
        //缓存中没有进行查询菜单
        //根据用户id获取角色
        List<Role> roles = userMapper.getRoleByUserId((long) userId);
        //没有角色直接返回
        if (CollectionUtil.isEmpty(roles)) {
            return ResponseResult.ok(List.of());
        }
        List<Long> roleIds = roles.stream().map(Role::getRoleId).collect(Collectors.toList());
        //根据角色获取菜单
        List<Menu> menuList = menuMapper.getMenuRoleIds(roleIds);
        //创建路由集合
        ArrayList<Router> routers = new ArrayList<>();
        //获取所有目录菜单
        List<Menu> mlList = menuList.stream().filter(menu -> "M".equals(menu.getMenuType())).toList();
        //转换成路由
        mlList.forEach(menu -> {
                    routers.add(new Router(menu));
                }
        );
        //获取所有菜单
        List<Menu> cdList = menuList.stream().filter(menu -> "C".equals(menu.getMenuType())).toList();
        for (Router router : routers) {
            List<Router> children = new ArrayList<>();
            for (Menu menu : cdList) {
                if (menu.getParentId().equals(router.getMenuId())) {
                    children.add(new Router(menu));
                }
            }
            router.setChildren(children);
        }
        //存储到缓存
        redisTemplate.opsForValue().set(RedisEnmu.CC_MENU_ROUTE_LIST + userId, JSONUtil.toJsonStr(routers), RedisEnmu.TIMEOUT);
        return ResponseResult.ok(routers);
    }

    /**
     * 获取所有菜单列表
     *
     * @return
     */
    @Override
    public ResponseResult<List<MenuOptionsVo>> allListOptions() {
        //获取所有菜单
        List<Menu> menuList = list();
        //获取所有目录菜单
        List<Menu> mlList = menuList.stream().filter(menu -> "M".equals(menu.getMenuType())).toList();
        //获取所有菜单
        List<Menu> cdList = menuList.stream().filter(menu -> "C".equals(menu.getMenuType())).toList();
        //返回结果对象
        List<MenuOptionsVo> optionsVoList = new ArrayList<>();
        //组合菜单
        for (Menu menu : mlList) {
            MenuOptionsVo optionsVo = new MenuOptionsVo(menu.getTitleZhCn(), menu.getMenuId().toString(), menu.getIcon());
            //遍历子菜单
            List<MenuOptionsVo> children = new ArrayList<>();
            for (Menu cMenu : cdList) {
                if (cMenu.getParentId().equals(menu.getMenuId())) {
                    children.add(new MenuOptionsVo(cMenu.getTitleZhCn(), cMenu.getMenuId().toString(), cMenu.getIcon()));
                }
            }
            if (CollectionUtil.isNotEmpty(children)) {
                optionsVo.setChildren(children);
            }
            optionsVoList.add(optionsVo);
        }
        return ResponseResult.ok(optionsVoList);
    }

}
